package gsi

import (
	"net"

	ghw_net "github.com/jaypipes/ghw/pkg/net"
	ghw_option "github.com/jaypipes/ghw/pkg/option"
	ghw_pci "github.com/jaypipes/ghw/pkg/pci"
)

type NetworkInferface struct {
	Name       string   `json:"name"`
	MTU        int      `json:"mtu"`
	MacAddress string   `json:"mac_address"`
	Flags      []string `json:"flags"`
	IpAddress  []string `json:"ip_address"`
}

type NetworkDevice struct {
	Name       string  `json:"name"`
	Driver     string  `json:"driver"`
	MacAddress string  `json:"mac_address"`
	PCIAddress *string `json:"pci_address,omitempty"`
	Speed      string  `json:"speed"`
	Duplex     string  `json:"duplex"`
}

type Network struct {
	NetworkInferface []NetworkInferface `json:"network_inferface"`
	NetworkDevice    []NetworkDevice    `json:"network_device"`
}

func (info *Network) getNetworkInfo() {
	ni, err := getNetworkInterfaceInfo()
	if err == nil {
		info.NetworkInferface = ni
	}

	nd, err := getNetworkDeviceInfo()
	if err == nil {
		info.NetworkDevice = nd
	}
}

func getNetworkInterfaceInfo() ([]NetworkInferface, error) {
	is, err := net.Interfaces()
	if err != nil {
		return nil, err
	}
	ret := make([]NetworkInferface, 0, len(is))
	for _, ifi := range is {

		var flags []string
		if ifi.Flags&net.FlagUp != 0 {
			flags = append(flags, "up")
		}
		if ifi.Flags&net.FlagBroadcast != 0 {
			flags = append(flags, "broadcast")
		}
		if ifi.Flags&net.FlagLoopback != 0 {
			flags = append(flags, "loopback")
		}
		if ifi.Flags&net.FlagPointToPoint != 0 {
			flags = append(flags, "pointtopoint")
		}
		if ifi.Flags&net.FlagMulticast != 0 {
			flags = append(flags, "multicast")
		}

		r := NetworkInferface{
			Name:       ifi.Name,
			MTU:        ifi.MTU,
			MacAddress: ifi.HardwareAddr.String(),
			Flags:      flags,
		}
		addrs, err := ifi.Addrs()
		if err == nil {
			r.IpAddress = make([]string, 0, len(addrs))
			for _, addr := range addrs {
				r.IpAddress = append(r.IpAddress, addr.String())
			}

		}
		ret = append(ret, r)
	}

	return ret, nil
}

func getNetworkDeviceInfo() ([]NetworkDevice, error) {

	netInfo, err := ghw_net.New(ghw_option.WithNullAlerter())
	if err != nil {
		return nil, err
	}
	pciInfo, err := ghw_pci.New(ghw_option.WithNullAlerter())
	if err != nil {
		return nil, err
	}
	pci2NicMap := make(map[string]*ghw_net.NIC)
	ret := make([]NetworkDevice, 0, len(netInfo.NICs))
	for _, nic := range netInfo.NICs {
		if nic.PCIAddress == nil {
			continue
		}
		pci2NicMap[*nic.PCIAddress] = nic
	}
	for _, pci := range pciInfo.Devices {
		if pci.Class.ID != "02" {
			continue
		}
		r := NetworkDevice{
			Driver:     pci.Driver,
			PCIAddress: &pci.Address,
		}
		nic, ok := pci2NicMap[pci.Address]
		if ok {
			r.Name = nic.Name
			r.MacAddress = nic.MacAddress
			r.Speed = nic.Speed
			r.Duplex = nic.Duplex
		}

		ret = append(ret, r)
	}

	return ret, nil
}

func (i *Network) YAMLString() string {
	return SafeYAML(i)
}

func (i *Network) JSONString(indent bool) string {
	return SafeJSON(i, indent)
}
